use std::mem;

pub fn get_price(data: &[u8], mut pos: usize) -> (i32, usize) {
    let mut pos_byte = 6;
    let bdata = indexbytes(data, pos);
    let mut intdata = (bdata & 0x3f) as i32;
    let sign = bdata & 0x40 != 0;

    if bdata & 0x80 != 0 {
        loop {
            pos += 1;
            let bdata = indexbytes(data, pos);
            intdata += ((bdata & 0x7f) as i32) << pos_byte;
            pos_byte += 7;

            if bdata & 0x80 != 0 {
                continue;
            } else {
                break;
            }
        }
    }

    pos += 1;

    if sign {
        intdata = -intdata;
    }

    (intdata, pos)
}

pub fn get_volume(ivol: i32) -> f64 {
    let logpoint = ivol >> (8 * 3);
    let hheax = ivol >> (8 * 3);
    let hleax = (ivol >> (8 * 2)) & 0xff;
    let lheax = (ivol >> 8) & 0xff;
    let lleax = ivol & 0xff;

    let dbl_1 = 1.0;
    let dbl_2 = 2.0;
    let dbl_128 = 128.0;

    let dwEcx = logpoint * 2 - 0x7f;
    let dwEdx = logpoint * 2 - 0x86;
    let dwEsi = logpoint * 2 - 0x8e;
    let dwEax = logpoint * 2 - 0x96;

    let tmpEax = if dwEcx < 0 { -dwEcx } else { dwEcx };

    let mut dbl_xmm6 = 0.0;
    dbl_xmm6 = f64::powi(2.0, tmpEax.abs());

    if dwEcx < 0 {
        dbl_xmm6 = 1.0 / dbl_xmm6;
    }

    let mut dbl_xmm4 = 0.0;

    if hleax > 0x80 {
        let mut tmpdbl_xmm3 = f64::powi(2.0, dwEdx + 1);
        let tmpdbl_xmm1 = 0.0;
        let dwtmpeax = dwEdx + 1;
        let mut dbl_xmm0 = f64::powi(2.0, dwEdx) * 128.0;
        dbl_xmm0 += (hleax & 0x7f) as f64 * tmpdbl_xmm3;
        dbl_xmm4 = dbl_xmm0;
    } else {
        let mut dbl_xmm0 = if dwEdx >= 0 {
            f64::powi(2.0, dwEdx) * hleax as f64
        } else {
            (1.0 / f64::powi(2.0, dwEdx)) * hleax as f64
        };
        dbl_xmm4 = dbl_xmm0;
    }

    let mut dbl_xmm3 = f64::powi(2.0, dwEsi) * lheax as f64;
    let mut dbl_xmm1 = f64::powi(2.0, dwEax) * lleax as f64;

    if hleax & 0x80 != 0 {
        dbl_xmm3 *= 2.0;
        dbl_xmm1 *= 2.0;
    }

    let dbl_ret = dbl_xmm6 + dbl_xmm4 + dbl_xmm3 + dbl_xmm1;

    dbl_ret
}

pub fn get_datetime(category: i32, buffer: &[u8], mut pos: usize) -> (i32, i32, i32, i32, i32, usize) {
    let mut year = 0;
    let mut month = 0;
    let mut day = 0i32;
    let mut hour = 15;
    let mut minute = 0;

    if category < 4 || category == 7 || category == 8 {
        let (zipday, tminutes) = unsafe {
            (mem::transmute::<[u8; 4], (u16, u16)>([
                buffer[pos],
                buffer[pos + 1],
                buffer[pos + 2],
                buffer[pos + 3],
            ]))
        };

        year = (zipday >> 11) as i32 + 2004;
        month = ((zipday % 2048) / 100) as i32;
        day = ((zipday % 2048) % 100) as i32;

        hour = (tminutes / 60) as i32;
        minute = (tminutes % 60) as i32;

        pos += 4;
    } else {
        let zipday = unsafe {
            mem::transmute::<[u8; 4], i32>([
                buffer[pos],
                buffer[pos + 1],
                buffer[pos + 2],
                buffer[pos + 3],
            ])
        };

        year = zipday / 10000;
        month = (zipday % 10000) / 100;
        day = zipday % 100;

        pos += 4;
    }

    (year, month, day, hour, minute, pos)
}

pub fn get_time(buffer: &[u8], mut pos: usize) -> (i32, i32, usize) {
    let tminutes = unsafe { mem::transmute::<[u8; 2], u16>([buffer[pos], buffer[pos + 1]]) };

    let hour = (tminutes / 60) as i32;
    let minute = (tminutes % 60) as i32;

    pos += 2;

    (hour, minute, pos)
}

pub fn indexbytes(data: &[u8], pos: usize) -> u8 {
    data[pos]
}
